<?php
/**
 * Created by PhpStorm.
 * User: 王松
 * Time: 2017/8/4 10:44
 */

namespace App\Project\Reserve\Statistics;

use App\Models\Reservation\Reservation;
use App\Models\Reservation\Role;
use App\Models\Reservation\Schedule;
use App\Project\Reserve\Exceptions\NoAuthToVisitStatisticsException;
use App\User;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Support\Arr;

class Visit
{
    protected $user;

    protected $reservation;

    protected $schedule;

    protected $doctors;

    protected $hospital_id;
    protected $am = false;

    public function __construct(User $user)
    {
        if ($user->isA('doctor')) {
            throw new NoAuthToVisitStatisticsException();
        }

        $this->user = $user;

        $this->reservation = new Reservation();

        $this->setHospital();

        if (request()->query->has('am')) {
            $this->am = (int)request()->query->get('am');
        }
        $this->doctors = $this->doctors();
    }

    /**
     * @param array $search
     * @return \Illuminate\Support\Collection|static
     */
    public function call($week)
    {
        $this->schedule($week);

        $result = $this->reservation($week);

        return $this->neaten($result, $week);
    }

    protected function neaten($result, $week)
    {
        list($start, $end) = is_array($week)? $week : [$week, $week];

        $start = Carbon::parse($start);
        $end   = Carbon::parse($end)->addDay();

        $doctors = $this->doctors->map(function (User $doctor) {

            return [
                'doctor_id' => $doctor->id,
                'name'      => $doctor->name,
                'room'      => '',
                'work'      => '',
                'setting'   => '',
                'status'    => ['key' => 0, 'value' => '停诊'],
            ];
        })->toArray();

        $collection = [];

        while ($start->notEqualTo($end)) {
            $date = $start->toDateString();

            if ($this->am !== 1) {
                if (Arr::has($result, $date . '.0')) {
                    $one = Arr::get($result, $date . '.0') + $doctors;
                } else {
                    $one = $doctors;
                }

                $one = collect($one)->map(function ($doctor, $doctor_id) use ($date) {
                    if (Arr::has($this->schedule, $date . '.' . $doctor_id . '.0')) {
                        $doctor['status'] = ['key' => 1, 'value' => '正常'];
                    }

                    return $doctor;
                })->toArray();

                Arr::set($collection, $date . '.0', $one);
            }

            if ($this->am !== 0) {
                if (Arr::has($result, $date . '.1')) {
                    $two = Arr::get($result, $date . '.1') + $doctors;
                } else {
                    $two = $doctors;
                }

                $two = collect($two)->map(function ($doctor, $doctor_id) use ($date) {
                    if (Arr::has($this->schedule, $date . '.' . $doctor_id . '.1')) {
                        $doctor['status'] = ['key' => 1, 'value' => '正常'];
                    }
                    return $doctor;
                })->toArray();

                Arr::set($collection, $date . '.1', $two);
            }

            $start->addDay();
        }

        return collect($collection)->map(function ($item) {

            return collect($item)->map(function ($item) {

                return collect($item)->sortByDesc(function ($item) {

                    return $item['status']['key'];
                })->values();
            });
        });
    }


    //  需要统计的所有医生
    protected function doctors()
    {
        return Role::where('name', 'doctor')->doctors($this->hospital_id)->first()->users->keyBy('id');
    }

    //  医生对应的排班情况
    protected function schedule($week)
    {
        $schedule = Schedule::whereTimeBetween($week)
                      ->whereIn('doctor_id', $this->doctors->pluck('id'))
                      ->get();

        $this->schedule = $schedule->sortBy('time')->groupBy('time')->map(function (Collection $item) {
            return $item->pluck('workload', 'doctor_id')->map(function ($item) {
                return collect($item)->map(function ($item) {
                    return collect($item)->sum(function ($item) {
                        return $item['number'];
                    });
                });
            });
        })->toArray();
    }

    protected function reservation($week)
    {
        $yu = Reservation::where(['hospital_id' => $this->hospital_id, 'status' => 2])
                         ->where('status', 2)
                         ->whereIn('doctor_id', $this->doctors->pluck('id')->toArray())
                         ->whereTimeBetween($week);
        if (false !== $this->am) {
            $yu = $yu->where('am', $this->am);
        }

        $data = [];

        $yu->get()->sortBy('time')->groupBy('time')->map(function (Collection $item, $time) use (&$data) {
            return $item->groupBy('am')->map(function (Collection $item, $am) use ($time, &$data) {

                return $item->groupBy('doctor_id')->map(function (Collection $item) use ($time, $am, &$data) {
                    $first = $item->first();

                    $setting = Arr::get($this->schedule, $time . '.' . $first->doctor_id . '.' . $am);

                    $data[$time][$am][$first->doctor_id] = [
                        'name'      => $this->doctors->get($first->doctor_id)->name,
                        'doctor_id' => $first->doctor_id,
                        'room'      => $first->room . ' 诊室',
                        'work'      => $item->count(),
                        'setting'   => $setting,
                        'status'    => $this->workStatus($item->count(), $setting),
                    ];

                    return $item;
                });
            });
        });

        return $data;
    }

    protected function workStatus($work, $setting)
    {
        if (empty($setting)) {
            return ['key' => 0, 'value' => '停诊'];
        }

        $ratio = $work / $setting;

        if ($ratio < 0.8) {
            return ['key' => 1, 'value' => '正常'];
        } elseif ($ratio < 1) {
            return ['key' => 2, 'value' => '约满'];
        } else {
            return ['key' => 3, 'value' => '爆满'];
        }
    }

    /**
     *
     */
    public function setHospital()
    {
        if ($this->user->isAn('admin')) {
            $this->hospital_id = app('request')->input('hospital_id');
        } else {
            $this->hospital_id = $this->user->hospital_id;
        }

        return $this;
    }

    /**
     * @param $am
     * @return $this
     */
    public function setAm($am)
    {
        $this->am = $am;

        return $this;
    }
}